widget: Cache clip from creating render node
authorBenjamin Otte <otte@redhat.com>
Sat, 31 Mar 2018 15:52:47 +0000 (17:52 +0200)
committerBenjamin Otte <otte@redhat.com>
Thu, 5 Apr 2018 12:56:38 +0000 (14:56 +0200)
When the clip changes that is passed to a snapshot function, we need to
create eventual cached render nodes because they might not have drawn
their whole area before.

Fixes issues with redrawing when scrolling.

gtk/gtksnapshot.c
gtk/gtksnapshotprivate.h
gtk/gtkwidget.c
gtk/gtkwidgetprivate.h

index ead1e5acafe4b851d6c695878fa6c4456e8ad1a0..14514a9689d4eac1038e18933c435830d2f20779 100644 (file)
@@ -1594,6 +1594,23 @@ gtk_snapshot_append_color (GtkSnapshot           *snapshot,
   gsk_render_node_unref (node);
 }
 
+gboolean
+gtk_snapshot_get_clip (GtkSnapshot     *snapshot,
+                       graphene_rect_t *out_clip)
+{
+  const GtkSnapshotState *current_state = gtk_snapshot_get_current_state (snapshot);
+
+  if (!current_state->has_clip)
+    return FALSE;
+
+  graphene_rect_offset_r (&current_state->clip,
+                          - current_state->translate_x,
+                          - current_state->translate_y,
+                          out_clip);
+
+  return TRUE;
+}
+
 /**
  * gtk_snapshot_clips_rect:
  * @snapshot: a #GtkSnapshot
index e5ddb600f0cf538eedc6ac7506524804b713db00..6e34d17c22a6e6b4b808d685c67b6a1905b59093 100644 (file)
@@ -99,11 +99,13 @@ struct _GtkSnapshotClass {
   GObjectClass           parent_class; /* it's really GdkSnapshotClass, but don't tell anyone! */
 };
 
-GtkSnapshot *   gtk_snapshot_new_child                  (GtkSnapshot            *parent,
-                                                         const char             *name,
-                                                         ...) G_GNUC_PRINTF (2, 3);
-void            gtk_snapshot_append_node_internal       (GtkSnapshot            *snapshot,
-                                                         GskRenderNode          *node);
+GtkSnapshot *           gtk_snapshot_new_child                  (GtkSnapshot            *parent,
+                                                                 const char             *name,
+                                                                 ...) G_GNUC_PRINTF (2, 3);
+void                    gtk_snapshot_append_node_internal       (GtkSnapshot            *snapshot,
+                                                                 GskRenderNode          *node);
+gboolean                gtk_snapshot_get_clip                   (GtkSnapshot            *snapshot,
+                                                                 graphene_rect_t        *out_clip);
 
 G_END_DECLS
 
index 3d9f967ce5b9caf758db35c7cf969857c1e0b743..039bc746fb06a986601428806113722cc63be1f9 100644 (file)
@@ -4021,6 +4021,7 @@ gtk_widget_queue_draw (GtkWidget *widget)
 
       priv->draw_needed = TRUE;
       g_clear_pointer (&priv->render_node, gsk_render_node_unref);
+      priv->render_node_has_clip = FALSE;
       gtk_widget_invalidate_paintable_contents (widget);
       if (_gtk_widget_get_has_surface (widget) &&
           _gtk_widget_get_realized (widget))
@@ -13816,6 +13817,8 @@ gtk_widget_snapshot (GtkWidget   *widget,
 {
   GtkWidgetPrivate *priv = widget->priv;
   graphene_rect_t offset_clip;
+  graphene_rect_t clip;
+  gboolean has_clip;
   double opacity;
 
   if (!_gtk_widget_is_drawable (widget))
@@ -13841,13 +13844,28 @@ gtk_widget_snapshot (GtkWidget   *widget,
   if (opacity <= 0.0)
     return;
 
-  if (priv->draw_needed)
+  has_clip = gtk_snapshot_get_clip (snapshot, &clip);
+
+  if (priv->draw_needed ||
+      (priv->render_node_has_clip && (!has_clip || !graphene_rect_contains_rect (&priv->render_node_clip, &clip))))
     {
       GskRenderNode *render_node;
+
       render_node = gtk_widget_create_render_node (widget, snapshot);
-      /* This can happen when nested drawing happens and a widget contains itself */
+      /* This can happen when nested drawing happens and a widget contains itself
+       * or when we replace a clipped area */
       g_clear_pointer (&priv->render_node, gsk_render_node_unref);
       priv->render_node = render_node;
+      if (has_clip)
+        {
+          priv->render_node_clip = clip;
+          priv->render_node_has_clip = TRUE;
+        }
+      else
+        {
+          priv->render_node_has_clip = FALSE;
+        }
+
       priv->draw_needed = FALSE;
     }
 
index ed65646ee23ddd744806ae325b2f9f324f22d226..2cc974a5e152022f4e164b8b1026c8da9ac93553 100644 (file)
@@ -78,6 +78,7 @@ struct _GtkWidgetPrivate
 
   /* Queue-draw related flags */
   guint draw_needed           : 1;
+  guint render_node_has_clip  : 1;
 
   /* Expand-related flags */
   guint need_compute_expand   : 1; /* Need to recompute computed_[hv]_expand */
@@ -145,8 +146,11 @@ struct _GtkWidgetPrivate
   /* The widget's requested sizes */
   SizeRequestCache requests;
 
-  /* The render node we draw or %NULL if not yet created. */
+  /* The render node we draw or %NULL if not yet created.*/
   GskRenderNode *render_node;
+  /* The clip that existed when the render node was drawn
+   * Ignored when render_node_has_clip == FALSE */
+  graphene_rect_t render_node_clip;
 
   GSList *paintables;